/*     */ package com.zimbra.cs.gal;
/*     */ 
/*     */ import com.google.common.base.Strings;
/*     */ import com.google.common.io.Closeables;
/*     */ import com.zimbra.common.account.Key.AccountBy;
/*     */ import com.zimbra.common.account.Key.DistributionListBy;
/*     */ import com.zimbra.common.account.ZAttrProvisioning.AccountStatus;
/*     */ import com.zimbra.common.account.ZAttrProvisioning.GalMode;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.soap.AccountConstants;
/*     */ import com.zimbra.common.soap.Element;
/*     */ import com.zimbra.common.soap.SoapFaultException;
/*     */ import com.zimbra.common.soap.SoapHttpTransport;
/*     */ import com.zimbra.common.soap.SoapProtocol;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.Pair;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.AccessManager;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.AuthToken;
/*     */ import com.zimbra.cs.account.DataSource;
/*     */ import com.zimbra.cs.account.Domain;
/*     */ import com.zimbra.cs.account.Group;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Provisioning.SearchGalResult;
/*     */ import com.zimbra.cs.account.accesscontrol.Rights.User;
/*     */ import com.zimbra.cs.account.gal.GalOp;
/*     */ import com.zimbra.cs.db.DbDataSource;
/*     */ import com.zimbra.cs.db.DbDataSource.DataSourceItem;
/*     */ import com.zimbra.cs.httpclient.URLUtil;
/*     */ import com.zimbra.cs.index.ContactHit;
/*     */ import com.zimbra.cs.index.ResultsPager;
/*     */ import com.zimbra.cs.index.SearchParams;
/*     */ import com.zimbra.cs.index.SortBy;
/*     */ import com.zimbra.cs.index.ZimbraHit;
/*     */ import com.zimbra.cs.index.ZimbraQueryResults;
/*     */ import com.zimbra.cs.ldap.LdapUtil;
/*     */ import com.zimbra.cs.mailbox.Contact;
/*     */ import com.zimbra.cs.mailbox.MailItem;
/*     */ import com.zimbra.cs.mailbox.MailItem.Type;
/*     */ import com.zimbra.cs.mailbox.MailServiceException;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mailbox.MailboxIndex;
/*     */ import com.zimbra.cs.mailbox.MailboxManager;
/*     */ import com.zimbra.cs.mailbox.Metadata;
/*     */ import com.zimbra.cs.mailbox.OperationContext;
/*     */ import com.zimbra.cs.mailbox.util.TypedIdList;
/*     */ import com.zimbra.cs.service.AuthProvider;
/*     */ import com.zimbra.cs.service.util.ItemId;
/*     */ import com.zimbra.soap.ZimbraSoapContext;
/*     */ import com.zimbra.soap.admin.type.DataSourceType;
/*     */ import com.zimbra.soap.type.GalSearchType;
/*     */ import java.io.IOException;
/*     */ import java.util.HashSet;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class GalSearchControl
/*     */ {
/*     */   private GalSearchParams mParams;
/*     */   
/*     */   public GalSearchControl(GalSearchParams params)
/*     */   {
/*  75 */     this.mParams = params;
/*     */   }
/*     */   
/*     */   private void checkFeatureEnabled(String extraFeatAttr) throws ServiceException {
/*  79 */     AuthToken authToken = this.mParams.getAuthToken();
/*  80 */     boolean isAdmin = authToken == null ? false : AuthToken.isAnyAdmin(authToken);
/*     */     
/*     */ 
/*  83 */     if (isAdmin) {
/*  84 */       return;
/*     */     }
/*     */     
/*  87 */     Account acct = this.mParams.getAccount();
/*  88 */     if (acct == null) {
/*  89 */       if (authToken != null) {
/*  90 */         acct = Provisioning.getInstance().get(Key.AccountBy.id, authToken.getAccountId());
/*     */       }
/*  92 */       if (acct == null) {
/*  93 */         throw ServiceException.PERM_DENIED("unable to get account for GAL feature checking");
/*     */       }
/*     */     }
/*  96 */     if (!acct.getBooleanAttr("zimbraFeatureGalEnabled", false)) {
/*  97 */       throw ServiceException.PERM_DENIED("GAL feature (zimbraFeatureGalEnabled) is not enabled");
/*     */     }
/*  99 */     if ((extraFeatAttr != null) && 
/* 100 */       (!acct.getBooleanAttr(extraFeatAttr, false))) {
/* 101 */       throw ServiceException.PERM_DENIED("GAL feature (" + extraFeatAttr + ") is not enabled");
/*     */     }
/*     */   }
/*     */   
/*     */   public void autocomplete() throws ServiceException
/*     */   {
/* 107 */     checkFeatureEnabled("zimbraFeatureGalAutoCompleteEnabled");
/*     */     
/* 109 */     this.mParams.setOp(GalOp.autocomplete);
/*     */     
/* 111 */     Account requestedAcct = this.mParams.getAccount();
/*     */     
/* 113 */     boolean useGalSyncAcct = requestedAcct == null ? true : requestedAcct.isGalSyncAccountBasedAutoCompleteEnabled();
/*     */     
/*     */ 
/* 116 */     if (useGalSyncAcct) {
/*     */       try {
/* 118 */         Account galAcct = this.mParams.getGalSyncAccount();
/* 119 */         if (galAcct == null)
/* 120 */           galAcct = getGalSyncAccount();
/* 121 */         accountSearch(galAcct);
/* 122 */         return;
/*     */       }
/*     */       catch (GalAccountNotConfiguredException e) {}
/*     */     }
/*     */     
/* 127 */     String query = Strings.nullToEmpty(this.mParams.getQuery());
/* 128 */     this.mParams.setQuery(query.replaceFirst("[*]*$", "*"));
/* 129 */     this.mParams.getResultCallback().reset(this.mParams);
/* 130 */     ldapSearch();
/*     */   }
/*     */   
/*     */   public void search() throws ServiceException
/*     */   {
/* 135 */     checkFeatureEnabled(null);
/*     */     
/* 137 */     String query = this.mParams.getQuery();
/*     */     
/*     */ 
/* 140 */     if (".".equals(query)) {
/* 141 */       this.mParams.setQuery(null);
/*     */     }
/* 143 */     this.mParams.setOp(GalOp.search);
/*     */     try {
/* 145 */       Account galAcct = this.mParams.getGalSyncAccount();
/* 146 */       if (galAcct == null)
/* 147 */         galAcct = getGalSyncAccount();
/* 148 */       accountSearch(galAcct);
/*     */     } catch (GalAccountNotConfiguredException e) {
/* 150 */       query = Strings.nullToEmpty(query);
/*     */       
/* 152 */       if (!query.endsWith("*"))
/* 153 */         query = query + "*";
/* 154 */       if (!query.startsWith("*"))
/* 155 */         query = "*" + query;
/* 156 */       this.mParams.setQuery(query);
/* 157 */       this.mParams.getResultCallback().reset(this.mParams);
/* 158 */       ldapSearch();
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/* 165 */   private static HashSet<String> SyncClients = new HashSet();
/*     */   
/*     */   public void sync()
/*     */     throws ServiceException
/*     */   {
/* 170 */     checkFeatureEnabled("zimbraFeatureGalSyncEnabled");
/*     */     
/* 172 */     String id = Thread.currentThread().getName() + " / " + this.mParams.getUserInfo();
/* 173 */     int capacity = this.mParams.getDomain().getGalSyncMaxConcurrentClients();
/* 174 */     boolean limitReached = true;
/*     */     
/* 176 */     synchronized (SyncClients)
/*     */     {
/*     */ 
/* 179 */       if ((capacity == 0) || (SyncClients.size() < capacity)) {
/* 180 */         SyncClients.add(id);
/* 181 */         limitReached = false;
/*     */       }
/*     */     }
/* 184 */     if (limitReached) {
/* 185 */       logCurrentSyncClients();
/*     */       
/* 187 */       this.mParams.getResultCallback().setNewToken(this.mParams.getGalSyncToken());
/* 188 */       this.mParams.getResultCallback().setThrottled(true);
/* 189 */       return;
/*     */     }
/*     */     try
/*     */     {
/* 193 */       this.mParams.setQuery("");
/* 194 */       this.mParams.setOp(GalOp.sync);
/* 195 */       this.mParams.setFetchGroupMembers(true);
/* 196 */       this.mParams.setNeedSMIMECerts(true);
/* 197 */       Account galAcct = this.mParams.getGalSyncAccount();
/* 198 */       GalSyncToken gst = this.mParams.getGalSyncToken();
/* 199 */       Domain domain = this.mParams.getDomain();
/*     */       
/*     */ 
/* 202 */       boolean useGalSyncAccount = (gst.doMailboxSync()) && ((this.mParams.isIdOnly()) || (domain.isLdapGalSyncDisabled()));
/* 203 */       if (useGalSyncAccount) {
/*     */         try {
/* 205 */           if (galAcct == null)
/* 206 */             galAcct = getGalSyncAccountForSync();
/* 207 */           accountSync(galAcct); return;
/*     */ 
/*     */         }
/*     */         catch (GalAccountNotConfiguredException e)
/*     */         {
/*     */ 
/* 213 */           this.mParams.getResultCallback().reset(this.mParams);
/*     */         }
/*     */       }
/* 216 */       if ((this.mParams.isIdOnly()) || (domain.isLdapGalSyncDisabled())) {
/*     */         try
/*     */         {
/* 219 */           if (getGalSyncAccount() != null) {
/* 220 */             this.mParams.getResultCallback().setFullSyncRecommended(true);
/*     */           }
/*     */         } catch (GalAccountNotConfiguredException e) {}
/*     */       }
/* 224 */       if (domain.isLdapGalSyncDisabled())
/*     */       {
/* 226 */         this.mParams.getResultCallback().setNewToken(this.mParams.getGalSyncToken());
/*     */       }
/*     */       else
/* 229 */         ldapSearch();
/*     */     } finally {
/* 231 */       synchronized (SyncClients) {
/* 232 */         SyncClients.remove(id);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void logCurrentSyncClients() {
/* 238 */     if (!ZimbraLog.galconcurrency.isDebugEnabled())
/* 239 */       return;
/* 240 */     StringBuilder buf = new StringBuilder();
/* 241 */     buf.append("limit reached, turning away ").append(this.mParams.getUserInfo());
/* 242 */     buf.append(", busy sync clients:");
/* 243 */     synchronized (SyncClients) {
/* 244 */       for (String id : SyncClients) {
/* 245 */         buf.append(" [").append(id).append("]");
/*     */       }
/*     */     }
/* 248 */     ZimbraLog.galconcurrency.debug(buf.toString());
/*     */   }
/*     */   
/*     */   private Account getGalSyncAccountForSync()
/*     */     throws GalSearchControl.GalAccountNotConfiguredException, ServiceException
/*     */   {
/* 254 */     GalSyncToken gst = this.mParams.getGalSyncToken();
/* 255 */     if ((gst == null) || (gst.isEmpty()) || (!gst.doMailboxSync()))
/* 256 */       return getGalSyncAccount();
/* 257 */     Domain d = this.mParams.getDomain();
/* 258 */     String[] accts = d.getGalAccountId();
/* 259 */     if (accts.length == 0)
/* 260 */       throw new GalAccountNotConfiguredException();
/* 261 */     Account ret = null;
/* 262 */     for (String acctId : accts) {
/* 263 */       if (gst.getChangeId(acctId) > 0) {
/* 264 */         Account a = Provisioning.getInstance().getAccountById(acctId);
/* 265 */         if ((a == null) || (!isValidGalSyncAccount(a))) break;
/* 266 */         ret = a; break;
/*     */       }
/*     */     }
/*     */     
/* 270 */     if (ret == null)
/* 271 */       throw new GalAccountNotConfiguredException();
/* 272 */     return ret;
/*     */   }
/*     */   
/*     */   private Account getGalSyncAccount() throws GalSearchControl.GalAccountNotConfiguredException, ServiceException {
/* 276 */     Domain d = this.mParams.getDomain();
/* 277 */     String[] accts = d.getGalAccountId();
/* 278 */     if (accts.length == 0)
/* 279 */       throw new GalAccountNotConfiguredException();
/* 280 */     Provisioning prov = Provisioning.getInstance();
/* 281 */     Account ret = null;
/* 282 */     for (String acctId : accts) {
/* 283 */       Account a = prov.getAccountById(acctId);
/* 284 */       if (a != null)
/*     */       {
/* 286 */         if (isValidGalSyncAccount(a)) {
/* 287 */           ret = a;
/* 288 */           if (Provisioning.onLocalServer(a))
/*     */             break;
/*     */         } }
/*     */     }
/* 292 */     if (ret == null)
/* 293 */       throw new GalAccountNotConfiguredException();
/* 294 */     return ret;
/*     */   }
/*     */   
/*     */   private boolean isValidGalSyncAccount(Account a) throws ServiceException {
/* 298 */     for (DataSource ds : a.getAllDataSources())
/* 299 */       if (ds.getType() == DataSourceType.gal)
/*     */       {
/*     */ 
/* 302 */         if (ds.getAttr("zimbraGalLastSuccessfulSyncTimestamp", null) == null)
/* 303 */           return false;
/* 304 */         if (ds.getAttr("zimbraGalStatus").compareTo("enabled") != 0)
/* 305 */           return false;
/* 306 */         if (ds.getAttr("zimbraDataSourceEnabled").compareTo("TRUE") != 0)
/* 307 */           return false;
/*     */       }
/* 309 */     return true;
/*     */   }
/*     */   
/*     */   private void generateSearchQuery(Account galAcct) throws ServiceException {
/* 313 */     String query = this.mParams.getQuery();
/* 314 */     String searchByDn = this.mParams.getSearchEntryByDn();
/*     */     
/* 316 */     GalSearchType type = this.mParams.getType();
/* 317 */     StringBuilder searchQuery = new StringBuilder();
/*     */     
/* 319 */     if (searchByDn != null) {
/* 320 */       searchQuery.append("#dn:(" + searchByDn + ")");
/* 321 */     } else if (!Strings.isNullOrEmpty(query)) {
/* 322 */       searchQuery.append("contact:\"");
/* 323 */       searchQuery.append(query.replace("\"", "\\\""));
/* 324 */       searchQuery.append("\" AND");
/*     */     }
/*     */     
/* 327 */     GalSearchQueryCallback queryCallback = this.mParams.getExtraQueryCallback();
/* 328 */     if (queryCallback != null) {
/* 329 */       String extraQuery = queryCallback.getMailboxSearchQuery();
/* 330 */       if (extraQuery != null) {
/* 331 */         ZimbraLog.gal.debug("extra search query: " + extraQuery);
/* 332 */         searchQuery.append(" (").append(extraQuery).append(") AND");
/*     */       }
/*     */     }
/*     */     
/* 336 */     ZAttrProvisioning.GalMode galMode = this.mParams.getDomain().getGalMode();
/* 337 */     boolean first = true;
/* 338 */     for (DataSource ds : galAcct.getAllDataSources())
/* 339 */       if (ds.getType() == DataSourceType.gal)
/*     */       {
/* 341 */         String galType = ds.getAttr("zimbraGalType");
/* 342 */         if (((galMode != ZAttrProvisioning.GalMode.ldap) || (galType.compareTo("zimbra") != 0)) && (
/*     */         
/* 344 */           (galMode != ZAttrProvisioning.GalMode.zimbra) || (galType.compareTo("ldap") != 0)))
/*     */         {
/* 346 */           if (first) searchQuery.append("("); else searchQuery.append(" OR");
/* 347 */           first = false;
/* 348 */           searchQuery.append(" inid:").append(ds.getFolderId());
/*     */         } }
/* 350 */     if (!first)
/* 351 */       searchQuery.append(")");
/* 352 */     switch (type) {
/*     */     case resource: 
/* 354 */       searchQuery.append(" AND #zimbraAccountCalendarUserType:RESOURCE");
/* 355 */       break;
/*     */     case group: 
/* 357 */       searchQuery.append(" AND #type:group");
/* 358 */       break;
/*     */     case account: 
/* 360 */       searchQuery.append(" AND !(#zimbraAccountCalendarUserType:RESOURCE)");
/* 361 */       break;
/*     */     }
/*     */     
/*     */     
/* 365 */     ZimbraLog.gal.debug("query: %s", new Object[] { searchQuery });
/* 366 */     this.mParams.parseSearchParams(this.mParams.getRequest(), searchQuery.toString());
/*     */   }
/*     */   
/*     */   private boolean generateLocalResourceSearchQuery(Account galAcct) throws ServiceException {
/* 370 */     String query = this.mParams.getQuery();
/* 371 */     StringBuilder searchQuery = new StringBuilder();
/* 372 */     if (!Strings.isNullOrEmpty(query)) {
/* 373 */       searchQuery.append("contact:\"");
/* 374 */       searchQuery.append(query.replace("\"", "\\\""));
/* 375 */       searchQuery.append("\" AND");
/*     */     }
/* 377 */     searchQuery.append(" #zimbraAccountCalendarUserType:RESOURCE");
/* 378 */     for (DataSource ds : galAcct.getAllDataSources())
/* 379 */       if (ds.getType() == DataSourceType.gal)
/*     */       {
/* 381 */         String galType = ds.getAttr("zimbraGalType");
/* 382 */         if (galType.compareTo("ldap") != 0)
/*     */         {
/* 384 */           searchQuery.append(" AND (");
/* 385 */           searchQuery.append(" inid:").append(ds.getFolderId());
/* 386 */           searchQuery.append(")");
/* 387 */           ZimbraLog.gal.debug("query: " + searchQuery.toString());
/* 388 */           this.mParams.parseSearchParams(this.mParams.getRequest(), searchQuery.toString());
/* 389 */           return true;
/*     */         } }
/* 391 */     return false;
/*     */   }
/*     */   
/*     */   private void accountSearch(Account galAcct) throws ServiceException, GalSearchControl.GalAccountNotConfiguredException {
/* 395 */     if (!galAcct.getAccountStatus().isActive()) {
/* 396 */       ZimbraLog.gal.info("GalSync account " + galAcct.getId() + " is in " + galAcct.getAccountStatus().name());
/* 397 */       throw new GalAccountNotConfiguredException();
/*     */     }
/* 399 */     if (Provisioning.onLocalServer(galAcct)) {
/* 400 */       if ((needResources()) && 
/* 401 */         (generateLocalResourceSearchQuery(galAcct)) && (!doLocalGalAccountSearch(galAcct)))
/*     */       {
/* 403 */         throw new GalAccountNotConfiguredException();
/*     */       }
/* 405 */       generateSearchQuery(galAcct);
/* 406 */       if (!doLocalGalAccountSearch(galAcct))
/* 407 */         throw new GalAccountNotConfiguredException();
/*     */     } else {
/*     */       try {
/* 410 */         if (!proxyGalAccountSearch(galAcct))
/* 411 */           throw new GalAccountNotConfiguredException();
/*     */       } catch (IOException e) {
/* 413 */         ZimbraLog.gal.warn("remote search on GalSync account failed for " + galAcct.getName(), e);
/*     */         
/* 415 */         throw new GalAccountNotConfiguredException();
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void accountSync(Account galAcct) throws ServiceException, GalSearchControl.GalAccountNotConfiguredException {
/* 421 */     if (!galAcct.getAccountStatus().isActive()) {
/* 422 */       ZimbraLog.gal.info("GalSync account " + galAcct.getId() + " is in " + galAcct.getAccountStatus().name());
/* 423 */       throw new GalAccountNotConfiguredException();
/*     */     }
/* 425 */     if (Provisioning.onLocalServer(galAcct)) {
/* 426 */       doLocalGalAccountSync(galAcct);
/*     */     } else {
/*     */       try {
/* 429 */         if (!proxyGalAccountSearch(galAcct))
/* 430 */           throw new GalAccountNotConfiguredException();
/*     */       } catch (IOException e) {
/* 432 */         ZimbraLog.gal.warn("remote sync on GalSync account failed for " + galAcct.getName(), e);
/*     */         
/* 434 */         this.mParams.getResultCallback().setNewToken(this.mParams.getGalSyncToken());
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private boolean doLocalGalAccountSearch(Account galAcct) {
/* 440 */     ZimbraQueryResults zqr = null;
/*     */     try {
/* 442 */       Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(galAcct);
/* 443 */       searchParams = this.mParams.getSearchParams();
/* 444 */       zqr = mbox.index.search(SoapProtocol.Soap12, new OperationContext(mbox), searchParams);
/* 445 */       ResultsPager pager = ResultsPager.create(zqr, searchParams);
/* 446 */       GalSearchResultCallback callback = this.mParams.getResultCallback();
/* 447 */       int num = 0;
/* 448 */       while (pager.hasNext()) {
/* 449 */         ZimbraHit hit = pager.getNextHit();
/* 450 */         if ((hit instanceof ContactHit)) {
/* 451 */           Element contactElem = callback.handleContact(((ContactHit)hit).getContact());
/* 452 */           if (contactElem != null)
/* 453 */             contactElem.addAttribute("sf", hit.getSortField(pager.getSortOrder()).toString());
/*     */         }
/* 455 */         num++;
/* 456 */         if (num == this.mParams.getLimit())
/*     */           break;
/*     */       }
/* 459 */       callback.setSortBy(zqr.getSortBy().toString());
/* 460 */       callback.setQueryOffset(searchParams.getOffset());
/* 461 */       callback.setHasMoreResult(pager.hasNext());
/*     */     } catch (Exception e) { SearchParams searchParams;
/* 463 */       ZimbraLog.gal.warn("search on GalSync account failed for %s", galAcct.getId(), e);
/* 464 */       return 0;
/*     */     } finally {
/* 466 */       Closeables.closeQuietly(zqr);
/*     */     }
/* 468 */     return true;
/*     */   }
/*     */   
/*     */   private void doLocalGalAccountSync(Account galAcct) throws ServiceException {
/* 472 */     GalSyncToken token = this.mParams.getGalSyncToken();
/* 473 */     Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(galAcct);
/* 474 */     OperationContext octxt = new OperationContext(mbox);
/* 475 */     GalSearchResultCallback callback = this.mParams.getResultCallback();
/* 476 */     HashSet<Integer> folderIds = new HashSet();
/* 477 */     Domain domain = this.mParams.getDomain();
/* 478 */     ZAttrProvisioning.GalMode galMode = domain.getGalMode();
/* 479 */     String syncToken = null;
/*     */     
/*     */ 
/*     */ 
/* 483 */     if ((galMode == ZAttrProvisioning.GalMode.ldap) && (domain.isGalAlwaysIncludeLocalCalendarResources()))
/*     */     {
/* 485 */       for (DataSource ds : galAcct.getAllDataSources())
/* 486 */         if (ds.getType() == DataSourceType.gal)
/*     */         {
/* 488 */           String galType = ds.getAttr("zimbraGalType");
/* 489 */           if (galType.compareTo("ldap") != 0)
/*     */           {
/* 491 */             int fid = ds.getFolderId();
/* 492 */             DbDataSource.DataSourceItem folderMapping = DbDataSource.getMapping(ds, fid);
/* 493 */             if (folderMapping.md != null)
/*     */             {
/* 495 */               folderIds.add(Integer.valueOf(fid));
/* 496 */               syncToken = LdapUtil.getEarlierTimestamp(syncToken, folderMapping.md.get("st"));
/* 497 */               int changeId = token.getChangeId(galAcct.getId());
/* 498 */               Pair<List<Integer>, TypedIdList> changed = mbox.getModifiedItems(octxt, changeId, MailItem.Type.CONTACT, folderIds);
/*     */               
/*     */ 
/* 501 */               int count = 0;
/* 502 */               for (Iterator i$ = ((List)changed.getFirst()).iterator(); i$.hasNext();) { int itemId = ((Integer)i$.next()).intValue();
/* 503 */                 MailItem item = mbox.getItemById(octxt, itemId, MailItem.Type.CONTACT);
/* 504 */                 if ((item instanceof Contact)) {
/* 505 */                   Contact c = (Contact)item;
/* 506 */                   String accountType = c.get("zimbraAccountCalendarUserType");
/* 507 */                   if ((accountType != null) && (accountType.equals("RESOURCE")))
/* 508 */                     callback.handleContact(c);
/*     */                 }
/* 510 */                 count++;
/* 511 */                 if (count % 100 == 0)
/* 512 */                   ZimbraLog.gal.debug("processing resources #" + count);
/*     */               }
/*     */             }
/*     */           }
/*     */         }
/*     */     }
/* 518 */     folderIds.clear();
/* 519 */     for (DataSource ds : galAcct.getAllDataSources())
/* 520 */       if (ds.getType() == DataSourceType.gal)
/*     */       {
/* 522 */         String galType = ds.getAttr("zimbraGalType");
/* 523 */         if (((galMode != ZAttrProvisioning.GalMode.ldap) || (galType.compareTo("zimbra") != 0)) && (
/*     */         
/* 525 */           (galMode != ZAttrProvisioning.GalMode.zimbra) || (galType.compareTo("ldap") != 0)))
/*     */         {
/* 527 */           int fid = ds.getFolderId();
/* 528 */           DbDataSource.DataSourceItem folderMapping = DbDataSource.getMapping(ds, fid);
/* 529 */           if (folderMapping.md != null)
/*     */           {
/* 531 */             folderIds.add(Integer.valueOf(fid));
/* 532 */             syncToken = LdapUtil.getEarlierTimestamp(syncToken, folderMapping.md.get("st"));
/*     */           } } }
/* 534 */     int changeId = token.getChangeId(galAcct.getId());
/* 535 */     List<Integer> deleted = null;
/* 536 */     if (changeId > 0) {
/*     */       try {
/* 538 */         deleted = mbox.getTombstones(changeId).getAllIds();
/*     */       } catch (MailServiceException e) {
/* 540 */         if ("mail.MUST_RESYNC" == e.getCode()) {
/* 541 */           ZimbraLog.gal.warn("sync token too old, deleted items will not be handled", e);
/*     */         } else {
/* 543 */           throw e;
/*     */         }
/*     */       }
/*     */     }
/*     */     
/* 548 */     Pair<List<Integer>, TypedIdList> changed = mbox.getModifiedItems(octxt, changeId, MailItem.Type.CONTACT, folderIds);
/*     */     
/*     */ 
/* 551 */     int count = 0;
/* 552 */     for (Iterator i$ = ((List)changed.getFirst()).iterator(); i$.hasNext();) { int itemId = ((Integer)i$.next()).intValue();
/* 553 */       MailItem item = mbox.getItemById(octxt, itemId, MailItem.Type.CONTACT);
/* 554 */       if ((item instanceof Contact))
/* 555 */         callback.handleContact((Contact)item);
/* 556 */       count++;
/* 557 */       if (count % 100 == 0)
/* 558 */         ZimbraLog.gal.debug("processing #" + count);
/*     */     }
/*     */     Iterator i$;
/* 561 */     if (deleted != null) {
/* 562 */       for (i$ = deleted.iterator(); i$.hasNext();) { int itemId = ((Integer)i$.next()).intValue();
/* 563 */         callback.handleDeleted(new ItemId(galAcct.getId(), itemId));
/*     */       }
/*     */     }
/* 566 */     GalSyncToken newToken = new GalSyncToken(syncToken, galAcct.getId(), mbox.getLastChangeID());
/* 567 */     ZimbraLog.gal.debug("computing new sync token for " + galAcct.getId() + ": " + newToken);
/* 568 */     callback.setNewToken(newToken);
/* 569 */     callback.setHasMoreResult(false);
/*     */   }
/*     */   
/*     */   private boolean proxyGalAccountSearch(Account galSyncAcct) throws IOException, ServiceException {
/*     */     try {
/* 574 */       Provisioning prov = Provisioning.getInstance();
/* 575 */       String serverUrl = URLUtil.getAdminURL(prov.getServerByName(galSyncAcct.getMailHost()));
/* 576 */       SoapHttpTransport transport = new SoapHttpTransport(serverUrl);
/* 577 */       AuthToken auth = this.mParams.getAuthToken();
/* 578 */       transport.setAuthToken(auth == null ? AuthProvider.getAdminAuthToken().toZAuthToken() : auth.toZAuthToken());
/*     */       
/* 580 */       ZimbraSoapContext zsc = this.mParams.getSoapContext();
/* 581 */       if (zsc != null) {
/* 582 */         transport.setResponseProtocol(zsc.getResponseProtocol());
/*     */         
/* 584 */         String requestedAcctId = zsc.getRequestedAccountId();
/* 585 */         String authTokenAcctId = zsc.getAuthtokenAccountId();
/* 586 */         if ((requestedAcctId != null) && (!requestedAcctId.equalsIgnoreCase(authTokenAcctId))) {
/* 587 */           transport.setTargetAcctId(requestedAcctId);
/*     */         }
/*     */       }
/* 590 */       Element req = this.mParams.getRequest();
/* 591 */       if (req == null) {
/* 592 */         req = Element.create(this.mParams.getProxyProtocol(), AccountConstants.SEARCH_GAL_REQUEST);
/* 593 */         req.addAttribute("type", this.mParams.getType().toString());
/* 594 */         req.addAttribute("limit", this.mParams.getLimit());
/* 595 */         req.addAttribute("name", this.mParams.getQuery());
/* 596 */         req.addAttribute("ref", this.mParams.getSearchEntryByDn());
/*     */       }
/* 598 */       req.addAttribute("galAcctId", galSyncAcct.getId());
/* 599 */       req.addAttribute("galAcctProxied", true);
/*     */       
/* 601 */       Element resp = transport.invokeWithoutSession(req.detach());
/* 602 */       GalSearchResultCallback callback = this.mParams.getResultCallback();
/*     */       
/* 604 */       if (callback.passThruProxiedGalAcctResponse()) {
/* 605 */         callback.handleProxiedResponse(resp);
/* 606 */         return true;
/*     */       }
/*     */       
/* 609 */       Iterator<Element> iter = resp.elementIterator("cn");
/* 610 */       while (iter.hasNext())
/* 611 */         callback.handleElement((Element)iter.next());
/* 612 */       iter = resp.elementIterator("deleted");
/* 613 */       while (iter.hasNext())
/* 614 */         callback.handleElement((Element)iter.next());
/* 615 */       String newTokenStr = resp.getAttribute("token", null);
/* 616 */       if (newTokenStr != null) {
/* 617 */         GalSyncToken newToken = new GalSyncToken(newTokenStr);
/* 618 */         ZimbraLog.gal.debug("computing new sync token for proxied account " + galSyncAcct.getId() + ": " + newToken);
/* 619 */         callback.setNewToken(newToken);
/*     */       }
/* 621 */       boolean hasMore = resp.getAttributeBool("more", false);
/* 622 */       callback.setHasMoreResult(hasMore);
/* 623 */       if (hasMore) {
/* 624 */         callback.setSortBy(resp.getAttribute("sortBy"));
/* 625 */         callback.setQueryOffset((int)resp.getAttributeLong("offset"));
/*     */       }
/*     */     } catch (SoapFaultException e) {
/* 628 */       GalSearchResultCallback callback = this.mParams.getResultCallback();
/* 629 */       if (callback.passThruProxiedGalAcctResponse()) {
/* 630 */         Element fault = e.getFault();
/* 631 */         callback.handleProxiedResponse(fault);
/*     */         
/*     */ 
/*     */ 
/*     */ 
/* 636 */         return true;
/*     */       }
/* 638 */       ZimbraLog.gal.warn("remote search on GalSync account failed for " + galSyncAcct.getName(), e);
/* 639 */       return false;
/*     */     }
/*     */     
/*     */ 
/* 643 */     return true;
/*     */   }
/*     */   
/*     */   public void ldapSearch() throws ServiceException {
/* 647 */     Domain domain = this.mParams.getDomain();
/* 648 */     ZAttrProvisioning.GalMode galMode = domain.getGalMode();
/* 649 */     GalSearchType stype = this.mParams.getType();
/* 650 */     Provisioning prov = Provisioning.getInstance();
/*     */     
/* 652 */     if (needResources()) {
/* 653 */       this.mParams.setType(GalSearchType.resource);
/* 654 */       this.mParams.createSearchConfig(GalSearchConfig.GalType.zimbra);
/*     */       try {
/* 656 */         prov.searchGal(this.mParams);
/*     */       } catch (Exception e) {
/* 658 */         throw ServiceException.FAILURE("ldap search failed", e);
/*     */       }
/* 660 */       this.mParams.setType(stype);
/*     */     }
/*     */     
/* 663 */     Integer ldapLimit = this.mParams.getLdapLimit();
/*     */     int limit;
/* 665 */     int limit; if (ldapLimit == null) {
/* 666 */       limit = this.mParams.getLimit();
/*     */     } else {
/* 668 */       limit = ldapLimit.intValue();
/*     */     }
/*     */     
/* 671 */     if ((limit == 0) && (GalOp.sync != this.mParams.getOp()) && (ldapLimit == null)) {
/* 672 */       limit = domain.getGalMaxResults();
/*     */     }
/* 674 */     this.mParams.setLimit(limit);
/*     */     
/*     */ 
/* 677 */     if (this.mParams.getOp() == GalOp.sync) {
/* 678 */       String galLastModified = domain.getGalDefinitionLastModifiedTimeAsString();
/* 679 */       if (galLastModified != null) {
/* 680 */         this.mParams.getResultCallback().setGalDefinitionLastModified(galLastModified);
/*     */       }
/*     */     }
/*     */     
/* 684 */     if (galMode == ZAttrProvisioning.GalMode.both)
/*     */     {
/* 686 */       this.mParams.setLimit(limit / 2);
/*     */     }
/* 688 */     GalSearchConfig.GalType type = GalSearchConfig.GalType.ldap;
/* 689 */     if (galMode != ZAttrProvisioning.GalMode.ldap)
/*     */     {
/* 691 */       type = GalSearchConfig.GalType.zimbra;
/*     */     }
/* 693 */     this.mParams.createSearchConfig(type);
/*     */     try {
/* 695 */       prov.searchGal(this.mParams);
/*     */     } catch (Exception e) {
/* 697 */       throw ServiceException.FAILURE("ldap search failed", e);
/*     */     }
/*     */     
/* 700 */     boolean hadMore = this.mParams.getResult().getHadMore();
/* 701 */     String newToken = this.mParams.getResult().getToken();
/* 702 */     if (this.mParams.getResult().getTokenizeKey() != null)
/* 703 */       hadMore = true;
/* 704 */     if (galMode == ZAttrProvisioning.GalMode.both)
/*     */     {
/* 706 */       this.mParams.createSearchConfig(GalSearchConfig.GalType.ldap);
/*     */       try {
/* 708 */         prov.searchGal(this.mParams);
/*     */       } catch (Exception e) {
/* 710 */         throw ServiceException.FAILURE("ldap search failed", e);
/*     */       }
/* 712 */       hadMore |= this.mParams.getResult().getHadMore();
/* 713 */       newToken = LdapUtil.getLaterTimestamp(newToken, this.mParams.getResult().getToken());
/* 714 */       if (this.mParams.getResult().getTokenizeKey() != null) {
/* 715 */         hadMore = true;
/*     */       }
/*     */     }
/* 718 */     if (this.mParams.getOp() == GalOp.sync)
/* 719 */       this.mParams.getResultCallback().setNewToken(newToken);
/* 720 */     this.mParams.getResultCallback().setHasMoreResult(hadMore);
/*     */   }
/*     */   
/*     */ 
/*     */   private boolean needResources()
/*     */     throws ServiceException
/*     */   {
/* 727 */     Domain domain = this.mParams.getDomain();
/* 728 */     return (domain.getGalMode() == ZAttrProvisioning.GalMode.ldap) && ((GalSearchType.all == this.mParams.getType()) || (GalSearchType.resource == this.mParams.getType())) && (domain.isGalAlwaysIncludeLocalCalendarResources());
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static boolean canExpandGalGroup(String groupName, String groupId, Account authedAcct)
/*     */   {
/* 742 */     if ((groupName == null) || (authedAcct == null)) {
/* 743 */       return false;
/*     */     }
/*     */     
/* 746 */     if (groupId == null) {
/* 747 */       return true;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 754 */     Provisioning prov = Provisioning.getInstance();
/*     */     
/* 756 */     if (prov.isDistributionList(groupName))
/*     */     {
/*     */       try
/*     */       {
/* 760 */         Group group = prov.getGroupBasic(Key.DistributionListBy.id, groupId);
/*     */         
/*     */ 
/*     */ 
/* 764 */         if (group == null) {
/* 765 */           ZimbraLog.gal.warn("unable to find group " + groupName + "(" + groupId + ") for permission checking");
/*     */           
/* 767 */           return false;
/*     */         }
/*     */         
/* 770 */         if (!AccessManager.getInstance().canDo(authedAcct, group, Rights.User.R_viewDistList, false)) {
/* 771 */           return false;
/*     */         }
/*     */       }
/*     */       catch (ServiceException e) {
/* 775 */         ZimbraLog.gal.warn("unable to check permission for gal group expansion: " + groupName);
/* 776 */         return false;
/*     */       }
/*     */     }
/*     */     
/* 780 */     return true;
/*     */   }
/*     */   
/*     */   private static class GalAccountNotConfiguredException
/*     */     extends Exception
/*     */   {
/*     */     private static final long serialVersionUID = 679221874958248740L;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/gal/GalSearchControl.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */